import random
import pygame

# 定义游戏中使用的常量(python中没有常量使用特定命名规则实现全部大写下划线命名)
# 屏幕大小
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
# 每秒刷新率
FRAME_PER_SEC = 60
# 定时器产生敌机事件
CREATE_ENEMY_EVENT = pygame.USEREVENT
# 定时器产生子弹事件，默认都从pygame.USEREVENT +1 后续添加以此类推
FIRE_BULLET_EVENT = pygame.USEREVENT + 1


# 封装敌机的精灵,继承Sprite
class GameSprite(pygame.sprite.Sprite):

    def __init__(self, image_name, speed=1):
        """
        初始化飞机
        :param image_name: 飞机图片名称
        :param speed: 飞机速度，默认为1
        """
        super().__init__()
        self.image = pygame.image.load(image_name)
        # 位置信息,image对象中封装图片位置 0,0 大小为图片大小
        self.rect = self.image.get_rect()
        self.speed = speed
        # 初始化定时器，每隔1s产生一架敌机

    def update(self, *args, **kwargs):
        """
        重写update方法更新自己的位置，让飞机在屏幕中垂直向下移动
        :param args:
        :param kwargs:
        :return:
        """
        self.rect.y += self.speed


class Background(GameSprite):
    """背景精灵"""

    def __init__(self, is_alt=False):
        """
        初始化背景
        :param is_alt: 是否为替换背景，如果是则默认位置在屏幕外
        """
        super().__init__("images/background.png", 4)
        if is_alt:
            self.rect.y = -self.rect.height

    def update(self, *args, **kwargs):
        """背景图片移出屏幕后需要回到顶部继续移动，父类不满足需求"""
        super().update(*args, **kwargs)
        if self.rect.y > self.rect.height:
            self.rect.y = -self.rect.height


class Enemy(GameSprite):
    """敌机"""

    def __init__(self):
        super().__init__("images/enemy1.png")
        # 随机速度
        self.speed = random.randint(1, 3)
        # 随机x位置
        self.rect.bottom = 0
        enemy_max_x = SCREEN_RECT.width - self.rect.width
        self.rect.x = random.randint(0, enemy_max_x)
        # print("x=%d,y=%d,speed=%d" % (self.rect.x, self.rect.y, self.speed))

    def update(self, *args, **kwargs):
        super().update(*args, **kwargs)
        # 飞机飞出屏幕后从精灵组删除回收内存
        if self.rect.y >= SCREEN_RECT.height:
            # 精灵.kill 将自己从所有精灵组删除
            self.kill()

    def __del__(self):
        """对象被回收，走该方法"""
        # print("敌机销毁了%s" % self.rect)
        pass


class Hero(GameSprite):
    """英雄飞机"""

    def __init__(self):
        # 英雄飞机默认不能移动，所以速度设置为0
        super().__init__("images/me1.png", 0)
        # 默认位置水平居中、垂直方向距离底部120
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.height - 120
        # 子弹精灵组
        self.bullet_group = pygame.sprite.Group()

    def update(self, *args, **kwargs):
        # 父类是垂直移动，英雄飞机横向移动，所以无需调用父类方法
        # 如果speed为正加上x位置会向右移动，如果speed为负数，加上x值越来越小，向左移动
        self.rect.x += self.speed
        # 边界检测
        if self.rect.x <= 0:
            self.rect.x = 0
        if self.rect.x >= SCREEN_RECT.width - self.rect.width:
            self.rect.x = SCREEN_RECT.width - self.rect.width

    def fire(self):
        # 发射子弹，将子弹添加到精灵组,每次发射三颗子弹
        for i in (0, 1, 2):
            bullet = Bullet()
            # 指定初始值,x中心点与飞机中心点一致，y在飞机正上方
            bullet.rect.centerx = self.rect.centerx
            bullet.rect.bottom = self.rect.y - i * 20
            self.bullet_group.add(bullet)


class Bullet(GameSprite):
    """子弹类"""

    def __init__(self):
        # speed为负数和y相加，y减少向上移动
        super().__init__("images/bullet1.png", -2)

    def update(self, *args, **kwargs):
        super().update(*args, **kwargs)
        # 如果子弹飞出屏幕，从精灵组中删除子弹
        if self.rect.y <= -self.rect.height:
            self.kill()

    def __del__(self):
        # print("子弹被回收 %s" % self.rect)
        pass
